package model;

import java.util.ArrayList;
import java.util.HashMap;

import model.location.ReferencePoint;
import model.location.ScreenLocationCalculator;
import model.location.SearchArea;
import model.location.WorldCoordinate;
import model.location.WorldLocationCalculator;
import model.webService.WebServiceConnector;
import view.Scanner;
import android.util.Log;

public class OnScreen 
{	
	private static final String TAG = OnScreen.class.getSimpleName();
	private Dimension _previewDimension;
	private Dimension _screenDimension;
	
	private SearchArea _searchArea;
	
	private float _leftToRightScale = 1f;
	private float angle;
	
	private ArrayList<ReferencePoint> _refPoints;	
	private HashMap<String, Snippet> _snippets;
	private Scanner _observer;
	
	private WebServiceConnector _webServiceConnector;
	
	//Singleton
	//Volatile means java will always get this variable from main memory
	private static volatile OnScreen INSTANCE;
	
	private OnScreen()
	{
		_snippets = new HashMap<String, Snippet>();
		_webServiceConnector = new WebServiceConnector();
	}

	public static OnScreen getInstance()
	{
		if(INSTANCE == null)
		{
			//synchronized means only one thread can use the variable at a time (locks the class)
			synchronized (OnScreen.class) 
			{
				if(INSTANCE == null)
				{
					INSTANCE = new OnScreen();
				}
			}
		}
		return INSTANCE;
	}

	/**
	 * Gets called when referencepoints are found by the decoder
	 * <p>Initiates the creation of a SearchArea and gets snippets in that area</p>
	 * @param updatedReferencePoints
	 */
	public void updateReferencePointList(ArrayList<ReferencePoint> updatedReferencePoints)
	{
		if(!updatedReferencePoints.isEmpty() && updatedReferencePoints.size() >= 1 && _screenDimension != null)
		{			
			this._refPoints = updatedReferencePoints;
		
			//Draw some points on the screen showing the location of the referencepoints (for testing purposes)
			drawPoints();
			
			//Calculate searchArea
			WorldLocationCalculator.calculateSearchArea(_refPoints);
			ScreenLocationCalculator.calculateScales();
			
			//Establish a connection to get Snippets from an Area
			
			//new ServiceConnection().execute();
		}	
		else
		{
			_searchArea = null;
			_observer.drawPoints(new float[0]);
		}
		
		checkArea();
		//else updateSnippetList(new HashMap<String, Snippet>());
	}
	
	/**
	 * Goes through the collection of Snippets and checks if they are in the SearchArea. If so, update their location.
	 */
	public void checkArea()
	{
		String subscribeIds = "";
		String unSubscribeIds= "";
		for (Snippet snippet : _snippets.values()) 
		{
			if(_searchArea != null && _searchArea.contains(snippet))
			{
				Log.d(TAG, String.format("Snippet found: %s", snippet.getId()));				
				
				if(!snippet.isInArea())
				{
					//Get renewed data for snippet
//					_webServiceConnector.subscribeToSnippet(snippet.getId());
					subscribeIds += (snippet.getId() + ",");
					snippet.setInArea(true);
				}
				
				
				ScreenLocationCalculator.calculateScreenLocation(snippet);
				
				if(snippet.countObservers() == 0)
					_observer.addSnippetView(snippet);
				
				
				//new ServiceConnection(snippet.getId()).execute();
			}
			else 
			{
				if(snippet.isInArea())
				{
//					_webServiceConnector.unSubscribeToSnippet(snippet.getId());
					unSubscribeIds += (snippet.getId() + ",");
					snippet.setInArea(false);
				}
			}
			
			snippet.notifyObservers();
		}
		
		_webServiceConnector.handleSubscriptions(subscribeIds, unSubscribeIds);
	}
	
	//For testing purposes
	private void drawPoints()
	{
		ArrayList<Float> points = new ArrayList<Float>();
		
		for (ReferencePoint refPoint : _refPoints) 
		{
			for (float f : refPoint.getScreenArea().getPoints()) 
			{
				points.add(f);
			}
		}
		
		float[] pointArray = new float[points.size()];
		
		for (int i = 0; i < points.size(); i++) 
		{
			pointArray[i] = points.get(i);
		}
		_observer.drawPoints(pointArray);
	}
	
	public SearchArea getSearchArea() {
		return _searchArea;
	}

	public void setSearchArea(SearchArea searchArea) {
		this._searchArea = searchArea;
	}

	public HashMap<String, Snippet> getSnippets() {
		return _snippets;
	}

	public void setSnippets(HashMap<String, Snippet> snippets) {
		this._snippets = snippets;
	}

	public WorldCoordinate getUpperLeft() 
	{
		return _searchArea.getUpperLeft();
	}

	public WorldCoordinate getLowerRight() 
	{
		return _searchArea.getLowerRight();
	}

	public float getAngle() 
	{
		return angle;
	}

	public void setAngle(float angle) 
	{
		this.angle = angle;
	}

	public void notifyScreenWithToast(String msg)
	{
		Log.e("TOAST", String.format("%s", msg));
		_observer.makeToast(msg);
	}

	public void setObserver(Scanner observer) {
		if(this._observer == null)
			this._observer = observer;
	}
	
	public Dimension getScreenDimension()
	{
		return _screenDimension;
	}
	
	public void setScreenDimension(int width, int height)
	{
		if(_screenDimension == null)
			_screenDimension = new Dimension(width, height);
	}
	
	public Dimension getPreviewDimension() {
		return _previewDimension;
	}

	public void setPreviewDimension(int width, int height) {
		_previewDimension = new Dimension(width, height);
	}

	public float getXCorrection()
	{
		return (_previewDimension.getWidth() / _screenDimension.getWidth());
	}
	
	public float getYCorrection()
	{
		return (_previewDimension.getHeight() / _screenDimension.getHeight());
	}
	
	public void setLeftToRightCodeScale(float scale)
	{
		this._leftToRightScale = scale;
	}
	
	public float getLeftTorightCodeScale()
	{
		return this._leftToRightScale;
	}
	
	public WebServiceConnector getWebServiceConnector()
	{
		return _webServiceConnector;
	}
}